package com.antong.cloud.common.security.token;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
import org.springframework.util.StringUtils;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 通过token获取身份认证信息时，用户身份信息转换器
 */
public class JwtUserAuthenticationConverter extends DefaultUserAuthenticationConverter {

    /**
     * 转换用户身份验证对象为map
     * token创建成功后，存储token信息时，会将token和身份认证信息全部转换为map存储
     * @param authentication
     * @return
     */
    @Override
    public Map<String, ?> convertUserAuthentication(Authentication authentication) {
        Map<String, Object> response = new LinkedHashMap();
        response.put("user_info", authentication.getPrincipal());
        if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
            response.put("authorities", AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
        }

        return response;
    }

    /**
     * 从map中提取用户身份验证对象
     * DefaultTokenServices.loadAuthentication 把存储的map信息转换为 身份认证对象
     *   调用链：
     *   DefaultAccessTokenConverter.extractAuthentication  获取 org.springframework.security.oauth2.provider.OAuth2Authentication
     *   》 DefaultUserAuthenticationConverter.extractAuthentication 获取 org.springframework.security.core.Authentication
     * @param map
     * @return
     */
    @Override
    public Authentication extractAuthentication(Map<String, ?> map) {
        Object principal = map.get("user_info");
        if(principal == null){
            return null;
        }
        Collection<? extends GrantedAuthority> authorities = getAuthorities(map);
        // 登录成功后可通过 SecurityContextHolder.getContext().getAuthentication().getPrincipal() 获取 principal 对象。
        return new UsernamePasswordAuthenticationToken(principal, "N/A", authorities);
    }


    private Collection<? extends GrantedAuthority> getAuthorities(Map<String, ?> map) {
        if (!map.containsKey("authorities")) {
            return AuthorityUtils.commaSeparatedStringToAuthorityList(StringUtils.arrayToCommaDelimitedString(null));
        } else {
            Object authorities = map.get("authorities");
            if (authorities instanceof String) {
                return AuthorityUtils.commaSeparatedStringToAuthorityList((String)authorities);
            } else if (authorities instanceof Collection) {
                return AuthorityUtils.commaSeparatedStringToAuthorityList(StringUtils.collectionToCommaDelimitedString((Collection)authorities));
            } else {
                throw new IllegalArgumentException("Authorities must be either a String or a Collection");
            }
        }
    }

}
